/*
 * Jenny Ruppen 09-730-391
 * Sebastien Goldberg 08-914-855
 * Henry Raymond 08-928-061
 * Stefan Mussato 09-752-270
 */
 
package ch.uzh.ifi.sopra.gruppe9.game;

import java.util.ArrayList;

import ch.uzh.ifi.sopra.gruppe9.game.Scenery.Location;

import com.jme3.scene.Node;


/**
 * Interactive in-game screen of the house of spies.
 */
public class HouseOfSpiesInterface extends Node {
	
	
	/**
	 * List of all registered mouseOver event elements of the house of spies.
	 */
	private ArrayList<IMouseOverable> mouseOverables = new ArrayList<IMouseOverable>();
	
	
	/**
	 * List of all registered click event elements of the house of spies.
	 */
	private ArrayList<IClickable> clickables = new ArrayList<IClickable>();
	
	
	/**
	 * List of all registered mouseOver event elements of the pile selection window.
	 */
	private ArrayList<IMouseOverable> pileSelectionMouseOverables = new ArrayList<IMouseOverable>();
	
	
	/**
	 * List of all registered click event elements of the pile selection window.
	 */
	private ArrayList<IClickable> pileSelectionClickables = new ArrayList<IClickable>();
	
	
	/**
	 * Geometry node of all content of the window.
	 */
	private Node houseOfSpies;
	
	
	/**
	 * Color constraint flag of the house of spies
	 */
	private GuiQuad colorConstraintIcon;
	
	
	/**
	 * Text telling player that it's not his turn
	 */
	private GuiText notYourTurn;

	
	/**
	 * Bribe button
	 */
	private GuiButton bribe;
	
	
	/**
	 * Close window button
	 */
	private GuiButton close;
	
	
	/**
	 * Selection of the amount of money the player wants to bribe with.
	 */
	private GuiSelection cost;
	
	
	/**
	 * Selection of the tower element market the player wants to bribe.
	 */
	private GuiSelection market;
	
	
	/**
	 * Parent node of all buying agents in the house of spies.
	 */
	private Node buyingAgentsNode;
	
	
	/**
	 * Window where the player can choose which buying agent he wants to use.
	 */
	private BuyingAgentInterface buyingAgentInterface;
	
	
	/**
	 * Window where the player can choose the tower element he wants to take from the tower element market's pile.
	 */
	private Node pileSelectionWindow;
	
	
	/**
	 * Selection of tower elements in the pile of the chosen tower element market from which the player can choose from.
	 */
	private GuiSelection pile;
	
	
	/**
	 * Parent nodes of all tower elements of the tower element selection in the pile selection window.
	 */
	private Node towerElements;
	
	
	/**
	 * Buy element button on the pile selection window.
	 */
	private GuiButton buyElement;
	
	
	/**
	 * Abstain from buying element button on the pile selection window.
	 */
	private GuiButton abstain;
	
	
	/**
	 * Text telling player that there are no elements in this pile.
	 */
	private GuiText noElementsInThePile;
	
	
	/**
	 * Constructor: Creates geometry.
	 */
	public HouseOfSpiesInterface() {
		
		houseOfSpies = new Node();
		
		GuiWindow window = new GuiWindow(GUI.Offset.SCENE, 29, 30, 710, 610, 50);
		houseOfSpies.attachChild(window);
		
		GuiText title = new GuiText("Haus der Spione", Fonts.getLarge());
		title.setPositionSize(GUI.Offset.SCENE, (768 - (int)title.getLineWidth()) / 2, 60, 51);
		houseOfSpies.attachChild(title);
		
		colorConstraintIcon = new GuiQuad();
		colorConstraintIcon.setPositionSize(GUI.Offset.SCENE, 349, 120, 80, 30, 51);
		colorConstraintIcon.setMaterial(MaterialManager.getColorConstraintFlags(), 0.0f, 0.0f, 1.0f, 0.2f);
		colorConstraintIcon.create();
		
		cost = new GuiSelection(true, false);
		
		String[] costs = {"3", "5"};
		
		for(int i = 0; i < 2; i++) {
			cost.addOption(i, GUI.Offset.SCENE, (384 - 80) + (i * 90), 180, 70, 50, 52);
			
			GuiText cost = new GuiText(costs[i]);
			cost.setPositionSize(GUI.Offset.SCENE, (384 - 35) + (i * 90), 195, 53);
			houseOfSpies.attachChild(cost);
			
			GuiQuad coin = new GuiQuad();
			coin.setPositionSize(GUI.Offset.SCENE, (384 - 72) + (i * 90), 185, 40, 40, 53);
			coin.setMaterial(MaterialManager.getPanelIcons(), 0.0f, 0.5f, 0.5f, 0.5f);
			houseOfSpies.attachChild(coin.create());
			
			GuiSlot slot = new GuiSlot(GUI.Offset.SCENE, (384 - 65) + (i * 90), 250, 40, 75, 51);
			houseOfSpies.attachChild(slot);			
		}

		houseOfSpies.attachChild(cost);
		cost.setAction(new ICallback() {
			public void run() { 
				if(cost.getValue() == -1) {
					market.deactivateAll();
				} else {
					market.removeAllValues();
					market.activateAll();
				}
			}
		});
		
		buyingAgentsNode = new Node();
		houseOfSpies.attachChild(buyingAgentsNode);
		
		market = new GuiSelection(true, false);
		
		for(int i = 0; i < 4; i++) {
			market.addOption(i, GUI.Offset.SCENE, (384 - 175) + (i * 90), 355, 80, 80, 52);
			
			GuiQuad coin = new GuiQuad();
			coin.setPositionSize(GUI.Offset.SCENE, (384 - 170) + (i * 90), 360, 70, 70, 53);
			coin.setMaterial(MaterialManager.getBribingIcons(), 0.25f * i, 0.0f, 0.25f, 1.0f);
			houseOfSpies.attachChild(coin.create());
					
		}
		
		houseOfSpies.attachChild(market);
		market.setAction(new ICallback() {
			public void run() { 
				if(market.getValue() == -1) {
					bribe.setActive(false);
				} else {
					bribe.setActive(true);
				}
			}
		});
		
		bribe = new GuiButton("Markt bestechen");
		bribe.setPositionSize(GUI.Offset.SCENE, (768 - 220) / 2, 465, 220, 51);
		bribe.setAction(new ICallback() { 
			public void run() {
				bribe.setActive(false);
				close.setActive(false);
				GUI.unregisterMouseOverable(mouseOverables);
				GUI.unregisterClickable(clickables);

				buyingAgentInterface = new BuyingAgentInterface(false, Game.board().getHouseOfSpies().getColorConstraint());

				buyingAgentInterface.setCancelAction(new ICallback() { 
					public void run() {
						bribe.setActive(true);
						close.setActive(true);
						GUI.registerMouseOverable(mouseOverables);
						GUI.registerClickable(clickables);
					}
				});
				buyingAgentInterface.setCarryOutActionAction(new ICallback() {
					public void run() {
						int[] buyingAgentIDs = buyingAgentInterface.getBuyingAgents();
						
						boolean partialSuccess = Game.board().getHouseOfSpies().doAction(Game.board().getMyIndex(), buyingAgentIDs[0], buyingAgentIDs[1], cost.getValue());
								
						if(!partialSuccess) {
							System.err.println("Error while executing house of spies action.");
							return;
						}
						showPileSelectionWindow();
					}
				});
			}
		});
		bribe.create();
		bribe.setActive(false);
		
		notYourTurn = new GuiText("Du bist nicht am Zug.");
		notYourTurn.setPositionSize(GUI.Offset.SCENE, (768 - (int)notYourTurn.getLineWidth()) / 2, 480, 51);
		
		market.deactivateAll(); // Cannot be further up in the code
		
		close = new GuiButton("Schliessen");
		close.setPositionSize(GUI.Offset.SCENE, (768 - 160) / 2, 555, 160, 51);
		close.setAction(new ICallback() { 
			public void run() { 
				GUI.changeState(GuiState.State.CLEAN_INGAME_SCREEN);
			}
		});
		houseOfSpies.attachChild(close.create());
		
		clickables.add(bribe);
		clickables.add(close);
		clickables.addAll(cost.getClickables());
		clickables.addAll(market.getClickables());
		
		mouseOverables.add(bribe);
		mouseOverables.add(close);
		mouseOverables.addAll(cost.getMouseOverables());
		mouseOverables.addAll(market.getMouseOverables());
		
		
		// Pile selection window
		
		pileSelectionWindow = new Node();
		
		GuiWindow pileSelectionWindowWindow = new GuiWindow(GUI.Offset.SCENE, 49, 150, 670, 370, 60);
		pileSelectionWindow.attachChild(pileSelectionWindowWindow);
		
		towerElements = new Node();
		pileSelectionWindow.attachChild(towerElements);
		
		noElementsInThePile = new GuiText("Der Turmteil-Vorrat von diesem Markt ist leer.");
		noElementsInThePile.setPositionSize(GUI.Offset.SCENE, (768 - (int)noElementsInThePile.getLineWidth()) / 2, 290, 61);
		
		buyElement = new GuiButton("Turmteil kaufen");
		buyElement.setPositionSize(GUI.Offset.SCENE, (768 - 420) / 2, 435, 200, 61);
		buyElement.setAction(new ICallback() { 
			public void run() {
				GUI.unregisterMouseOverable(mouseOverables);
				GUI.unregisterClickable(clickables);
				GUI.unregisterMouseOverable(pileSelectionMouseOverables);
				GUI.unregisterClickable(pileSelectionClickables);
				if(houseOfSpies.hasChild(pileSelectionWindow)) {
					houseOfSpies.detachChild(pileSelectionWindow);
				}
				boolean success = false;
				if(market.getValue() == 0) {
					success = Game.board().getBaseElementMarket().doAction(Game.board().getMyIndex(), 0, 0, pile.getValue(), 0);
				} else if(market.getValue() == 1) {
					success = Game.board().getMiddleElementMarket().doAction(Game.board().getMyIndex(), 0, 0, pile.getValue(), 0);
				} else if(market.getValue() == 2) {
					success = Game.board().getWindowElementMarket().doAction(Game.board().getMyIndex(), 0, 0, pile.getValue(), 0);
				} else if(market.getValue() == 3) {
					success = Game.board().getRoofElementMarket().doAction(Game.board().getMyIndex(), 0, 0, pile.getValue(), 0);
				}
						
				if(!success) {
					System.err.println("Error while executing house of spies action.");
					return;
				}
				GUI.changeState(GuiState.State.CLEAN_INGAME_SCREEN);
			}
		});
		pileSelectionWindow.attachChild(buyElement.create());
		
		abstain = new GuiButton("Verzichten");
		abstain.setPositionSize(GUI.Offset.SCENE, (768 + 40) / 2, 435, 200, 61);
		abstain.setAction(new ICallback() { 
			public void run() { 
				boolean success = false;
				if(market.getValue() == 0) {
					success = Game.board().getBaseElementMarket().doAction(Game.board().getMyIndex(), 0, 0, -1, 0);
				} else if(market.getValue() == 1) {
					success = Game.board().getMiddleElementMarket().doAction(Game.board().getMyIndex(), 0, 0, -1, 0);
				} else if(market.getValue() == 2) {
					success = Game.board().getWindowElementMarket().doAction(Game.board().getMyIndex(), 0, 0, -1, 0);
				} else if(market.getValue() == 3) {
					success = Game.board().getRoofElementMarket().doAction(Game.board().getMyIndex(), 0, 0, -1, 0);
				}
						
				if(!success) {
					System.err.println("Error while executing house of spies action.");
					return;
				}
				GUI.changeState(GuiState.State.CLEAN_INGAME_SCREEN);
			}
		});
		pileSelectionWindow.attachChild(abstain.create());
		
		pileSelectionClickables.add(buyElement);
		pileSelectionClickables.add(abstain);
		
		pileSelectionMouseOverables.add(buyElement);
		pileSelectionMouseOverables.add(abstain);
		
	}
	
	
	/**
	 * Show pile selection window.
	 */
	private void showPileSelectionWindow() {
		houseOfSpies.attachChild(pileSelectionWindow);
		towerElements.detachAllChildren();
		
		if(pileSelectionWindow.hasChild(pile)) {
			pileSelectionClickables.removeAll(pile.getClickables());
			pileSelectionMouseOverables.removeAll(pile.getMouseOverables());
			pileSelectionWindow.detachChild(pile);
		}
		if(pileSelectionWindow.hasChild(noElementsInThePile)) {
			pileSelectionWindow.detachChild(noElementsInThePile);
		}
		
		pile = new GuiSelection(true, false);
		pile.setAction(new ICallback() {
			public void run() { 
				if(pile.getValue() == -1) {
					buyElement.setActive(false);
				} else {
					buyElement.setActive(true);
				}
			}
		});
		pileSelectionWindow.attachChild(pile);
		
		ArrayList<TowerElement> pileElements = null;
		if(market.getValue() == 0) {
			pileElements = Game.board().getBaseElementMarket().getTowerElementPile();
		} else if(market.getValue() == 1) {
			pileElements = Game.board().getMiddleElementMarket().getTowerElementPile();
		} else if(market.getValue() == 2) {
			pileElements = Game.board().getWindowElementMarket().getTowerElementPile();
		} else if(market.getValue() == 3) {
			pileElements = Game.board().getRoofElementMarket().getTowerElementPile();
		}
		
		int playerMoney = Game.board().me().getMoneyBalance();
		
		int	numberOfElements = pileElements.size();
		int lastTopElement = ((numberOfElements + 1) / 2);
		for(int i = 0; i < numberOfElements; i++) {
			int xOffset;
			int yOffset;
			if(numberOfElements <= 6) {
				xOffset = ((768 - (70 * numberOfElements)) / 2) + (70 * i);
				yOffset = 250;
			} else if(i < lastTopElement) {
				xOffset = ((768 - (70 * lastTopElement)) / 2) + (70 * i);
				yOffset = 190;
			} else {
				xOffset = ((768 - (70 * (numberOfElements - lastTopElement))) / 2) + (70 * (i - lastTopElement));
				yOffset = 310;	
			}
			
			TowerElement element = pileElements.get(i);
			
			pile.addOption(element.getId(), GUI.Offset.SCENE, xOffset + 5, yOffset, 60, 60, 62);
				
			GuiTowerElement guiElement = new GuiTowerElement(element);
			towerElements.attachChild(guiElement.get2D(GUI.Offset.SCENE, xOffset + 35, yOffset + 43, 63, 1.0f));
			
			GuiText cost = new GuiText(Integer.toString(element.getCost()));
			cost.setPositionSize(GUI.Offset.SCENE, xOffset + 46, yOffset + 70, 63);
			towerElements.attachChild(cost);
			
			GuiQuad coin = new GuiQuad();
			coin.setPositionSize(GUI.Offset.SCENE, xOffset + 8, yOffset + 60, 40, 40, 63);
			coin.setMaterial(MaterialManager.getPanelIcons(), 0.0f, 0.5f, 0.5f, 0.5f);
			towerElements.attachChild(coin.create());
			
			if(element.getCost() > playerMoney) {
				pile.deactivate(element.getId());
			}
		}
		
		if(numberOfElements == 0) {
			pileSelectionWindow.attachChild(noElementsInThePile);
		}
		
		buyElement.setActive(false);
		
		pileSelectionClickables.addAll(pile.getClickables());
		pileSelectionMouseOverables.addAll(pile.getMouseOverables());
		
		GUI.registerClickable(pileSelectionClickables);
		GUI.registerMouseOverable(pileSelectionMouseOverables);
		
	}
	
	
	/**
	 * Attach all needed geometry and register all mouseOver and click events.
	 */
	public void show() {
		Scenery.startCamAnimation(Location.HOUSE_OF_SPIES, new ICallback() {
			public void run() {
		
				GUI.getHouseOfSpies().attachChild(houseOfSpies);
				GUI.registerMouseOverable(mouseOverables);
				GUI.registerClickable(clickables);
		
				GUI.getHouseOfSpies().updateHouseOfSpies();
			}
		});
	}
	
	
	/**
	 * Detach all geometry and unregister all mouseOver and click events.
	 */
	public void hide() {
		this.detachChild(houseOfSpies);
		GUI.unregisterMouseOverable(mouseOverables);
		GUI.unregisterClickable(clickables);
		Scenery.startCamAnimation(Location.BASIC_SCENE_CAMERA, null);
	}


	/**
	 * Updates bank amount selection when the server sends a update message.
	 */
	public void updateHouseOfSpies() {
		
		cost.clearSelection();
		market.clearSelection();
		close.setActive(true);
		
		BuyingAgent.Color colorConstraint = Game.board().getHouseOfSpies().getColorConstraint();
		if(colorConstraint == BuyingAgent.Color.NONE && houseOfSpies.hasChild(colorConstraintIcon)) {
			houseOfSpies.detachChild(colorConstraintIcon);
		}
		if(colorConstraint != BuyingAgent.Color.NONE && !houseOfSpies.hasChild(colorConstraintIcon)) {
			houseOfSpies.attachChild(colorConstraintIcon);
		}
		if(colorConstraint == BuyingAgent.Color.BLUE) {
			colorConstraintIcon.changeTextureCoords(0.0f, 0.0f, 1.0f, 0.2f);
		} else if(colorConstraint == BuyingAgent.Color.GREEN) {
			colorConstraintIcon.changeTextureCoords(0.0f, 0.2f, 1.0f, 0.2f);
		} else if(colorConstraint == BuyingAgent.Color.ORANGE) {
			colorConstraintIcon.changeTextureCoords(0.0f, 0.4f, 1.0f, 0.2f);
		} else if(colorConstraint == BuyingAgent.Color.PURPLE) {
			colorConstraintIcon.changeTextureCoords(0.0f, 0.6f, 1.0f, 0.2f);
		} else if(colorConstraint == BuyingAgent.Color.YELLOW) {
			colorConstraintIcon.changeTextureCoords(0.0f, 0.8f, 1.0f, 0.2f);
		}
		
		int[] useOfSlots = Game.board().getHouseOfSpies().getBuyingAgentSlots();
		buyingAgentsNode.detachAllChildren();
		for(int i = 0; i < 2; i++) {
			if(useOfSlots[i] == 1) {
				buyingAgentsNode.attachChild(GuiBuyingAgent.getColor2D(colorConstraint, GUI.Offset.SCENE, (384 - 65) + (i * 90), 250, 52));
			} else if(useOfSlots[i] == 2) {
				buyingAgentsNode.attachChild(GuiBuyingAgent.getColor2D(BuyingAgent.Color.NONE, GUI.Offset.SCENE, (384 - 65) + (i * 90), 250, 52));
			}
		}
		
		if(Game.board().getTurn() == Game.board().getMyIndex()) {
			if(houseOfSpies.hasChild(notYourTurn)) {
				houseOfSpies.detachChild(notYourTurn);
			}
			if(!houseOfSpies.hasChild(bribe)) {
				houseOfSpies.attachChild(bribe);
			}
			cost.activateAll();
			for(int i = 0; i < 2; i++) {
				if(useOfSlots[i] == 1) {
					cost.deactivate(i);
				} else if(useOfSlots[i] == 2) {
					cost.deactivate(i);
				}
			}
		} else {
			if(!houseOfSpies.hasChild(notYourTurn)) {
				houseOfSpies.attachChild(notYourTurn);
			}
			if(houseOfSpies.hasChild(bribe)) {
				houseOfSpies.detachChild(bribe);
			}
			cost.deactivateAll();
		}
	}
	
}
